<?php
/*
 * Copyright 2010 Johannes M. Schmitt
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * Class for reading dependency files generated by calcdeps.py
 * 
 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 */
class GoogleClosureDependencies
{
	/**
	 * @var array
	 */
  private $_dependencies;
  
  /**
   * @var array
   */
  private $_files;
  
  /**
   * @param string $depsDefinitions
   * @return GoogleClosureDependencies
   */
  public final function __construct($depsDefinitions)
  {
    $this->_dependencies = array();
    $this->_files = array();
    
    if (preg_match_all('#goog.addDependency\("([^"]+)", (\[[^\]]+\]), (\[[^\]]*\])\)#',
      $depsDefinitions, $lineMatches))
    {
      for ($i=0, $c=count($lineMatches[0]); $i<$c; $i+=1)
      {
        $lineMatches[2][$i] = str_replace("'", '"', $lineMatches[2][$i]);
        $lineMatches[3][$i] = str_replace("'", '"', $lineMatches[3][$i]);
        
        $provides = json_decode($lineMatches[2][$i], true);
        $requires = json_decode($lineMatches[3][$i], true);
        
        foreach ($provides as $provide)
        {
        	if (isset($this->_dependencies[$provide]))
            throw new RuntimeException(sprintf('"%s" has already been provided.', $provide));
            
          $this->_dependencies[$provide] = $requires;
          $this->_files[$provide] = $lineMatches[1][$i];
        }
      }
    }
    else
      throw new RuntimeException('No dependency definitions were found.');
  }
  
  /**
   * Shortcut for reading dependencies from a file
   * 
   * @param string $filePath
   * @return GoogleClosureDependencies
   */
  public final static function fromFile($filePath)
  {
    if (!file_exists($filePath) || !is_readable($filePath))
      throw new InvalidArgumentException('Could not read from file.');
      
    $class = get_called_class();
    return new $class(file_get_contents($filePath));
  }
  
  /**
   * Returns the files that are required for using the given class.
   * Files are relative to the base.js file that was used when 
   * running calcdeps.py
   * 
   * @param string $class
   * @param string $basePath if set, the returned path is absolute instead of
   * 												 relative to the base.js file
   * @return array
   */
  public final function getRequiredFiles($class, $basePath = '', $firstCall = true)
  {
    if (!isset($this->_dependencies[$class]))
      throw new InvalidArgumentException(sprintf('"%s" has never been provided.', $class));
     
    // calculate the correct base path (only necessary on unix systems)
    if ($firstCall && false !== strpos($basePath, '/plugins/'))
    {
    	$pos = strrpos($basePath, 'web/');
    	$subPath = substr($basePath, $pos+3);
    	$basePath = substr($basePath, 0, $pos-1);
    	$pluginName = substr($basePath, strrpos($basePath, '/') + 1);
    	$basePath = sfConfig::get('sf_web_dir').'/'.$pluginName.$subPath;
    }
    
    $relativePath = $this->_files[$class];
    $absolutePath = $basePath;
    while (strpos($relativePath, '../') === 0)
    {
    	$relativePath = substr($relativePath, 3);
    	$absolutePath = dirname($absolutePath);
    }
    $filePath = realpath($absolutePath.'/'.$relativePath);
    $files = array($filePath);
    
    foreach ($this->_dependencies[$class] as $require)
      $files = array_merge($this->getRequiredFiles($require, $basePath, false), $files);
      
    if ($firstCall)
    {
    	$files = array_unique($files);
    	array_unshift($files, $basePath.'base.js');
    }	
    	
    return $files;
  }
}